#include "camera3d.h"
#include <glm/gtc/matrix_transform.hpp>

namespace kanon
{
    Camera3d::Camera3d(glm::vec3 position)
        : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(2.5f),
        MouseSensitivity(0.1f), Zoom(45.0f) 
    {
        Position = position;
        WorldUp = glm::vec3(0.0f, 1.0f, 0.0f);
        Yaw = -90.0f;
        Pitch = 0.0f;
        updateCameraVectors();
        width = 0;
        height = 0;
    }

    void Camera3d::setWindowSize(uint32_t width, uint32_t height)
    {
        this->width = width;
        this->height = height;
    }

    void Camera3d::moveForward(float offset)
    {
        Position += Front * offset;
    }

    void Camera3d::moveUp(float offset)
    {
        Position += Up * offset;
    }

    void Camera3d::moveRight(float offset)
    {
        Position += Right * offset;
    }

    void Camera3d::zoomOut(float dz)
    {
        Zoom += dz;
    }

    void Camera3d::rotate(float xoffset, float yoffset, bool constrainPitch) 
    {
        xoffset *= MouseSensitivity;
        yoffset *= MouseSensitivity;

        Yaw += xoffset;
        Pitch += yoffset;

        if (constrainPitch) {
            if (Pitch > 89.0f) Pitch = 89.0f;
            if (Pitch < -89.0f) Pitch = -89.0f;
        }
        updateCameraVectors();
    }

    void Camera3d::updateCameraVectors()
    {
        glm::vec3 front;
        front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
        front.y = sin(glm::radians(Pitch));
        front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
        Front = glm::normalize(front);
        Right = glm::normalize(glm::cross(Front, WorldUp));
        Up = glm::normalize(glm::cross(Right, Front));
    }

    glm::mat4 Camera3d::getViewMatrix() const
    {
        return glm::lookAt(Position, Position + Front, Up);
    }

    glm::mat4 Camera3d::getProjectionMatrix() const
    {
        float aspectRatio = (float)width / height;
        return glm::perspective(glm::radians(Zoom), aspectRatio, 0.1f, 100.0f);
    }

}
